#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <interface.h>

#define     BUFLEN      1024
#define     LISTENQ     8

#define PUT     1
#define GET     2
#define DELETE  4
#define EXIT    8
#define erraise(string) do{\
    perror(string);\
    exit(-1);\
}while(0)

static void print_usage();
int com_resolving(char *command, char *key, char *value);

int main()
{
    int listenfd, connfd;
    struct sockaddr_in servaddr;
    char buffer[BUFLEN];
    char key[128], value[1024];
    char config_file[128] = "kvs.conf";

//    daemon(0, 0);
    
    kv_init(config_file);
    
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        erraise("can not open socket file:");

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(8080);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if ((bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) < 0)
        erraise("bind error:");
    
    if ((listen(listenfd, LISTENQ)) < 0)
        erraise("listen error:");
    
   
    for (;;)
    {
        int type;
        int n;
       
        memset(buffer, 0, sizeof(buffer));
       
        if ((connfd = accept(listenfd, (struct sockaddr *)NULL, NULL)) < 0)
            erraise("accept error:");

        n = read(connfd, buffer, sizeof(buffer));

        if (n > 0)
        {
            if ((type = com_resolving(buffer, key, value)) > 0)
            {
                if (type == PUT)
                {
                    kv_put(key, strlen(key), value, strlen(value));
                }
                else if (type == GET)
                {
                    memset(value, 0, sizeof(value));
                    kv_get(key, strlen(value), value, 1024);
                    write(connfd, value, sizeof(value));
                }
                else if (type == DELETE)
                {
                    kv_delete(key, strlen(key));
                }
                else if (type == EXIT)
                {
                    kv_exit();
                    close(connfd);
                }
            }
            else
            {
                write(connfd, buffer, 1024);
            }

        }
        close(connfd);

    }
    return 0;
}

int com_resolving(char *command, char *key, char *value)
{
    int i = 0, com_index, key_index, val_index;
    char com[32];
    
    for (i = 0; command[i] == ' '; i++);
    
    memset(com, 0, sizeof(com));
    
    for (com_index = 0; isalpha(command[i]);)
    {
        if (command[i] <= 'z' && command[i] >= 'a')
            command[i] -= 'a' - 'A';

        com[com_index++] = command[i++];
    }
    
    for (; command[i] == ' '; i++);

    memset(key, 0, 128);
    
    for (key_index = 0; isalnum(command[i]); )
    {
        key[key_index++] = command[i++];
    }

    for (; command[i] == ' '; i++);
    
    memset(value, 0, sizeof(value)); 
    
    for (val_index = 0; isalnum(command[i]); )
    {
        value[val_index++] = command[i++];
    }
    
    if (0 == strcmp(com, "PUT"))
        return PUT;

    if (0 == strcmp(com, "GET"))
        return GET;
    if (0 == strcmp(com, "DELETE"))
        return DELETE;
    if (0 == strcmp(com, "EXIT"))
        return EXIT;
    
    memset(command, 0, sizeof(command));
    print_usage(command);
    return 0;
}

static void print_usage(char *buffer)
{
    sprintf(buffer+strlen(buffer), "Usage: COMMAND\t[key [value]]\n\n");
    sprintf(buffer+strlen(buffer), "COMMAND:\n");
    sprintf(buffer+strlen(buffer), "\tPUT\t\tput a key-value-pair into storage system\n");
    sprintf(buffer+strlen(buffer), "\tGET\t\tget a record with the given key, value will be ignored if given\n");
    sprintf(buffer+strlen(buffer), "\tDELETE\t\tdelete a record with the given key, value will be ignored if given\n");
    sprintf(buffer+strlen(buffer), "\tEXIT\t\texit, both key and value given will be ignored\n");
}
